/* @flow */

import type Watcher from './watcher'
import { remove } from '../util/index'
import config from '../config'

let uid = 0

/**
 * A dep is an observable that can have multiple
 * directives subscribing to it.
 */
export default class Dep {
  static target: ?Watcher;
  id: number;
  subs: Array<Watcher>;

  constructor () {
    this.id = uid++
    this.subs = []
  }

  // 将接收到的观察者添加到 Dep 实例对象的 subs 数组中(addSub 方法才是真正用来收集观察者的方法)
  addSub (sub: Watcher) {
    this.subs.push(sub)
  }

  removeSub (sub: Watcher) {
    remove(this.subs, sub)
  }

  // 在depend中收藏依赖实际上是通过addDep(当前 Dep 实例对象作为参数)实现的，再次判断Dep.target是否存在的原因是dep.depend在其它地方也会被调用
  depend () {
    if (Dep.target) {
      Dep.target.addDep(this)
    }
  }

  // 遍历当前 Dep 实例对象的 subs 属性中所保存的所有观察者对象,并逐个调用观察者对象的 update 方法（即触发响应的实现机制）,
  notify () {
    // stabilize the subscriber list first
    const subs = this.subs.slice()

    if (process.env.NODE_ENV !== 'production' && !config.async) {
      // subs aren't sorted in scheduler if not running async
      // we need to sort them now to make sure they fire in correct
      // order
      subs.sort((a, b) => a.id - b.id)
    }
    for (let i = 0, l = subs.length; i < l; i++) {
      // 重新求值的操作是在 update 方法中进行的
      subs[i].update()
    }
  }
}

// the current target watcher being evaluated.
// this is globally unique because there could be only one
// watcher being evaluated at any time.
// Dep类的静态属性，初始为Null
Dep.target = null
const targetStack = []
/**
 * pushTarget 函数会将接收到的参数赋值给 Dep.target 属性 即 为Dep.target赋值
 * @param {观察者实例} target 
 */
export function pushTarget (target: ?Watcher) {
  targetStack.push(target)
  // Dep.target 保存着一个观察者对象，这个观察者对象就是即将要收集的目标
  Dep.target = target
}

export function popTarget () {
  targetStack.pop()
  Dep.target = targetStack[targetStack.length - 1]
}
